package com.gill.touka.service;

import com.alibaba.fastjson.JSON;
import com.gill.touka.domain.dto.AuditDTO;
import com.gill.touka.domain.dto.ShareDTO;
import com.gill.touka.domain.dto.UserDTO;
import com.gill.touka.domain.entity.RocketmqTransactionLog;
import com.gill.touka.domain.entity.Share;
import com.gill.touka.domain.enums.AuditStatusEnum;
import com.gill.touka.mapper.RocketmqTransactionLogMapper;
import com.gill.touka.mq.AddBonusMsg;
import com.gill.touka.feign.client.UserCenterFeignClient;
import com.gill.touka.mapper.ShareMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.Objects;
import java.util.UUID;

@Slf4j
@Service
public class ShareService {

    @Autowired
    private ShareMapper shareMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserCenterFeignClient feignClient;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private Source source;

    @Autowired
    private RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

    public ShareDTO findById(Integer id){
        Share share = shareMapper.selectByPrimaryKey(id);
        if(share == null) return null;//测试的时候为了不报错使用，不涉及具体业务
        Integer userId = share.getUserId();
        // 通过feign来进行http调用
        UserDTO userDTO = feignClient.findById(userId);
        if(userDTO == null) return null;//测试的时候为了不报错使用，不涉及具体业务
        ShareDTO result = new ShareDTO();
        BeanUtils.copyProperties(share,result);
        result.setWxNickname(userDTO.getWxNickname());
        return result;
    }

    /**
     * 审核分享内容
     * @param id share 的id
     * @param auditDTO 审核
     */
//    @Transactional(rollbackFor = {Exception.class})//该事务不靠谱，不能控制MQ发送消息
    public Share auditById(Integer id, AuditDTO auditDTO){
        // 1、查询当前的share是否存在，不存在抛异常；当share存在时，若已经被审核则抛异常
        Share share = shareMapper.selectByPrimaryKey(id);
        if(share == null){
            throw new IllegalArgumentException("share不存在");
        }
        else if(!Objects.equals(share.getAuditStatus(), AuditStatusEnum.NOT_YET.toString())){
            throw new IllegalArgumentException("该share已经被审核");
        }
        // 若审核通过，发送半消息
        if(Objects.equals(auditDTO.getAuditStatusEnum(),AuditStatusEnum.PASS)){
            sendMessageInTransaction(id,auditDTO);
        }
        else{// 若审核不通过，则不用为用户添加积分（即不需要发送消息）
            auditByIdInDB(id,auditDTO);
        }
        share.setAuditStatus("该结果无任何意义");
        return share;
    }

    /**
     * 审核通过，发送半消息（RocketMQ实现分布式事务1）
     * @param id shareId
     * @param auditDTO 审核内容
     */
    private void sendMessageInTransaction(Integer id,AuditDTO auditDTO){
        // 构建消息
        AddBonusMsg msg = AddBonusMsg.builder()
                .id(id)
                .bonus(50)
                .build();
        // 发送半消息
        String transactionId = UUID.randomUUID().toString();
        source.output().send(MessageBuilder
                .withPayload(msg)
                .setHeader(RocketMQHeaders.TRANSACTION_ID,transactionId)//实现分布式事务使用
                .setHeader("share_id",id)
                .setHeader("auditDTO",JSON.toJSONString(auditDTO))
                .build());
        log.info("share审核通过：RocketMQ的半消息已经发送");
    }

    /**
     * 审核（数据库操作）
     * @param id shareId
     * @param auditDTO 审核内容
     */
    @Transactional(rollbackFor = {Exception.class})//出现异常回滚
    public void auditByIdInDB(Integer id, AuditDTO auditDTO) {
        Share share = Share.builder()
                .id(id)
                .auditStatus(auditDTO.getAuditStatusEnum().toString())
                .reason(auditDTO.getReason())
                .build();
        shareMapper.updateByPrimaryKeySelective(share);
    }

    /**
     * 审核（数据库操作）并且记录事务日志
     * @param id shareId
     * @param auditDTO 审核内容
     * @param transactionId 事务id
     */
    @Transactional(rollbackFor = {Exception.class})//出现异常回滚
    public void auditByIdWithRocketMqLog(Integer id, AuditDTO auditDTO, String transactionId) {
        this.auditByIdInDB(id, auditDTO);

        rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder()
                        .transactionId(transactionId)
                        .log("审核分享...")
                        .build()
        );
    }

    /**
     * 查看事务id是否已经存在
     * @param transactionId 事务id
     */
    public Boolean existTransactionId(String transactionId){
        // select * from xxx where transaction_id = xxx
        RocketmqTransactionLog transactionLog = this.rocketmqTransactionLogMapper.selectOne(
                RocketmqTransactionLog.builder()
                        .transactionId(transactionId)
                        .build()
        );
        return transactionLog != null;
    }
}
